﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using nDeveloper.BO.Base.Domain;
using System.Collections;
using nDeveloper.BO.Info;
using nDeveloper.UI.Base.Windows.Common;
using System.IO;

namespace nDeveloper.UI.Windows.IDE
{
    /// <summary>
    /// This class makes it possible to import default data from .csv files.
    /// @Author Drill
    /// </summary>
    public partial class frmImportDefaultData : Form
    {
        private ArrayList ent; //ent has all the entity names
        private DataTable table = new DataTable(); //table has a list of selected table columns and their default values, if needed

        public frmImportDefaultData()
        {
            InitializeComponent();
        }

        /// <summary>
        /// btnSearchFile_Click opens a dialog for the user to choose a .csv file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSearchFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofn = new OpenFileDialog();
            ofn.Filter = "Arquivos de texto CSV (*.csv)|*.csv|Arquivos de texto (*.txt)|*.txt|Todos os tipos (*.*)|*.*";
            ofn.Title = "Localizar arquivo para importação";
            if (ofn.ShowDialog() == DialogResult.OK)
            {
                this.txtFile.Text = ofn.FileName;
            }
        }

        /// <summary>
        /// btnDown_Click set a table line in dgvFields to go down
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDown_Click(object sender, EventArgs e)
        {
            if (this.dgvFields.SelectedRows.Count > 0)
            {
                int lowOrder = this.dgvFields.SelectedRows[0].Index + 1;
                if (lowOrder < this.table.Rows.Count)
                {
                    int upOrder = lowOrder + 1;

                    DataRow[] upRow = this.table.Select("Ordem = '" + upOrder.ToString() + "'");
                    DataRow[] downRow = this.table.Select("Ordem = '" + lowOrder.ToString() + "'");
                    upRow[0]["Ordem"] = lowOrder;
                    downRow[0]["Ordem"] = upOrder;
                }
            }
        }

        /// <summary>
        /// chkIgnore_CheckedChanged sets visibility settings about an ignored field to be added
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkIgnore_CheckedChanged(object sender, EventArgs e)
        {
            if (this.chkIgnore.Checked)
            {
                this.cmbField.Enabled = false;
                this.txtDefaultValue.Enabled = false;
                this.txtDefaultValue.Text = "";
                this.btnAdd.Enabled = true;
                this.cmbField.SelectedIndex = -1;
                this.cmbEntity.Enabled = false;
            }
            else
            {
                this.cmbField.Enabled = true;
                this.txtDefaultValue.Enabled = true;
                this.btnAdd.Enabled = false;
                if (this.table.Rows.Count <= 0)
                {
                    this.cmbEntity.Enabled = true;
                }
            }
        }

        /// <summary>
        /// frmImportDefaultData_Load set some initial settings
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmImportDefaultData_Load(object sender, EventArgs e)
        {
            this.table.Columns.Add("Ordem");
            this.table.Columns.Add("Campo");
            this.table.Columns.Add("Valor padrão");
            this.table.DefaultView.Sort = "Ordem ASC";

            this.dgvFields.DataSource = this.table;

            SystemDataDictionaryEntity se = new SystemDataDictionaryEntity();
            this.ent = se.GetEntityList();
            ent.Sort(new SystemDataDictionaryInfoEntityComparer());

            this.cmbEntity.DisplayMember = "Name";
            this.cmbEntity.ValueMember = "Name";
            this.cmbEntity.DataSource = ent;
        }

        /// <summary>
        /// cmbEntity_SelectedIndexChanged loads cmbFileds items according to cmbEntity selection
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbEntity_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.cmbField.Items.Clear();
            this.btnAdd.Enabled = false;
            if (this.cmbEntity.SelectedIndex >= 0)
            {
                SystemDataDictionaryEntityColumns cl = new SystemDataDictionaryEntityColumns();
                ArrayList col = cl.GetEntityColumnsList(this.cmbEntity.SelectedValue.ToString());

                //TODO: UNPOG this
                foreach (SystemDataDictionaryInfoEntityColumns c in col)
                {
                    this.cmbField.Items.Add(c.Name);
                }
            }

        }

        /// <summary>
        /// btnAdd_Click adds a csv field configuration for the default data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAdd_Click(object sender, EventArgs e)
        {
            int order = this.table.Rows.Count + 1;
            if (this.chkIgnore.Checked == true)
            {
                table.Rows.Add(new Object[] { order, "", "" });
            }
            else
            {
                table.Rows.Add(new Object[] { order, this.cmbField.SelectedItem.ToString(),
                                                        this.txtDefaultValue.Text});
            }
            this.dgvFields.DataSource = table;

            if (this.chkIgnore.Checked == false)
            {
                this.cmbEntity.Enabled = false;
            }
        }

        /// <summary>
        /// cmbField_SelectedIndexChanged enables add button when there is a valid field selected
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbField_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.cmbField.SelectedIndex >= 0)
            {
                this.btnAdd.Enabled = true;
            }
        }

        /// <summary>
        /// btnUp_Click sets the chosen line to go up and resets the correct order numbers
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnUp_Click(object sender, EventArgs e)
        {
            if (this.dgvFields.SelectedRows.Count > 0)
            {
                int lowOrder = this.dgvFields.SelectedRows[0].Index;
                if (lowOrder > 0)
                {
                    int upOrder = lowOrder + 1;

                    DataRow[] upRow = this.table.Select("Ordem = '" + upOrder.ToString() + "'");
                    DataRow[] downRow = this.table.Select("Ordem = '" + lowOrder.ToString() + "'");
                    upRow[0]["Ordem"] = lowOrder;
                    downRow[0]["Ordem"] = upOrder;
                }
            }
        }

        /// <summary>
        /// btnRemove_Click removes the selected field of configuration
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRemove_Click(object sender, EventArgs e)
        {
            if (this.dgvFields.SelectedRows.Count > 0)
            {
                int selectedOrder = this.dgvFields.SelectedRows[0].Index + 1;
                DataRow[] rows = this.table.Select("Ordem >= '" + selectedOrder.ToString() + "'");
                this.table.Rows.Remove(rows[0]);

                for (int i = 1; i < rows.Length; i++)
                {
                    rows[i]["Ordem"] = Convert.ToInt32(rows[i]["Ordem"]) - 1;
                }

                if (this.table.Rows.Count <= 0 && chkIgnore.Checked == false)
                {
                    this.cmbEntity.Enabled = true;
                }
            }
        }

        /// <summary>
        /// btnCancel_Click does nothing and close the window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// btnImport_Click does the whole import stuff
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnImport_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.txtFile.Text == "")
                {
                    Tela.ExibeErro("Arquivo de texto (.csv) deve ser selecionado!");
                    return;
                }
                if (this.table.Rows.Count == 0)
                {
                    Tela.ExibeErro("Campos de configuração devem ser adicionados!");
                    return;
                }

                String[] lines;

                try
                {
                    /*FileStream fs = File.OpenRead(this.txtFile.Text);
                    StreamReader sr = new StreamReader(fs, true);
                    string text = sr.ReadToEnd();
                    lines = text.Split('\n');*/


                    /*FileStream fsw = File.OpenWrite("temp.txt");
                    StreamWriter sw = new StreamWriter(fsw, Encoding.UTF8);
                    sw.Write(text);*/

                    lines = File.ReadAllLines(this.txtFile.Text, frmImportDefaultData.GetFileEncoding(this.txtFile.Text));

                }
                catch (Exception ex)
                {
                    Tela.ExibeErro("O arquivo não pôde ser aberto! Ocorreu o seguinte erro: " + ex.Message);
                    return;
                }

                if ((lines.Length > 0 && chkFirstLine.Checked == false) || (lines.Length > 1 && chkFirstLine.Checked == true))
                {
                    int startFrom = 0;
                    if (chkFirstLine.Checked == true)
                    {
                        startFrom = 1;
                    }

                    DataTable dt = new DataTable();

                    ArrayList ignoredOrders = new ArrayList();

                    for (int i = 1; i <= this.table.Rows.Count; i++)
                    {
                        DataRow[] rows = this.table.Select("Ordem = '" + i.ToString() + "'");
                        string campo = rows[0]["Campo"].ToString();
                        if (campo == "")
                        {
                            ignoredOrders.Add(i - 1);
                            continue;
                        }
                        dt.Columns.Add(campo);
                    }

                    dt.TableName = this.cmbEntity.Text;

                    for (int i = startFrom; i < lines.Length; i++)
                    {
                        DataRow rowToAdd = dt.NewRow();
                        string[] split = lines[i].Split(';');

                        for (int j = 0, k = 0; j < split.Length; j++)
                        {
                            if (ignoredOrders.Contains(j))
                                continue;
                            if (split[j].Trim() == "")
                            {
                                split[j] = this.table.Rows[j]["Valor padrão"].ToString();
                            }
                            rowToAdd[k] = split[j];
                            k++;
                        }
                        dt.Rows.Add(rowToAdd);
                    }

                    DataSet ds = new DataSet();
                    ds.Tables.Add(dt);

                    try
                    {
                        SystemDataDictionaryDefaultValue def = new SystemDataDictionaryDefaultValue();
                        def.Save(ds, this.cmbEntity.Text);
                    }
                    catch (Exception ex2)
                    {
                        Tela.ExibeErro("Os dados não puderam ser salvos! O seguinte erro ocorreu: " + ex2.Message);
                        return;
                    }
                    Tela.ExibeAviso("Os dados padrão foram importados com sucesso!");
                }
            }
            catch (Exception ex3)
            {
                Tela.ExibeErro("Verifique se todas as colunas do .csv foram configuradas! O seguinte erro ocorreu: " + ex3.Message);
                return;
            }

        }

        /// <summary>
        /// GetFileEncoding gets the encoding of a file. this method has to be somewhere else, as it is public
        /// and static. I suggest the adition of other encoding formats in UnicodeEncodings set.
        /// </summary>
        /// <param name="FileName"></param>
        /// <returns></returns>
        public static Encoding GetFileEncoding(String FileName)

        // Return the Encoding of a text file.  Return Encoding.Default if no Unicode
        // BOM (byte order mark) is found.
        {
            Encoding Result = null;

            FileInfo FI = new FileInfo(FileName);

            FileStream FS = null;

            try
            {
                FS = FI.OpenRead();

                Encoding[] UnicodeEncodings = { Encoding.BigEndianUnicode, Encoding.Unicode, Encoding.UTF8 };

                for (int i = 0; Result == null && i < UnicodeEncodings.Length; i++)
                {
                    FS.Position = 0;

                    byte[] Preamble = UnicodeEncodings[i].GetPreamble();

                    bool PreamblesAreEqual = true;

                    for (int j = 0; PreamblesAreEqual && j < Preamble.Length; j++)
                    {
                        PreamblesAreEqual = Preamble[j] == FS.ReadByte();
                    }

                    if (PreamblesAreEqual)
                    {
                        Result = UnicodeEncodings[i];
                    }
                }
            }
            catch (System.IO.IOException)
            {
            }
            finally
            {
                if (FS != null)
                {
                    FS.Close();
                }
            }

            if (Result == null)
            {
                Result = Encoding.Default;
            }

            return Result;
        }


    }
}
